package com.video.dao;

import com.alibaba.dashscope.audio.asr.recognition.Recognition;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionParam;
import com.alibaba.dashscope.audio.asr.transcription.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.video.tool.AutoVideoFilterProcessor;
import com.video.tool.VideoGifOverlay;
import com.video.utils.constant.UrlConstant;
import org.apache.commons.io.FilenameUtils;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;

import javax.sound.sampled.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;

public class VideoManager {

    private VideoManager() {
    }

    private static final class VideoManagerHolder {
        private static final VideoManager instance = new VideoManager();
    }

    public static VideoManager getInstance() {
        return VideoManagerHolder.instance;
    }

    public void move(File srcFile, File outFile, File bottomGifFile) throws Exception {
        final File filterFile = new File(srcFile.getParentFile(), FilenameUtils.getBaseName(srcFile.getAbsolutePath()) + "_filter." + FilenameUtils.getExtension(srcFile.getAbsolutePath()));
        AutoVideoFilterProcessor.applyAutoFilter(srcFile.getAbsolutePath(), filterFile.getAbsolutePath());
        VideoGifOverlay.addGifToVideo(srcFile.getAbsolutePath(), outFile.getAbsolutePath(), bottomGifFile.getAbsolutePath());
    }

    /**
     * 分享视频中的音频
     *
     * @param inputVideo
     * @param outputAudio
     * @return
     */
    public boolean extractAudio(String inputVideo, String outputAudio) {
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputVideo);
        FFmpegFrameRecorder recorder = null;
        boolean success = true;
        try {
            grabber.start();
            recorder = new FFmpegFrameRecorder(outputAudio, grabber.getAudioChannels());
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_MP3);
            recorder.setSampleRate(grabber.getSampleRate());
            recorder.start();

            Frame frame;
            while ((frame = grabber.grabFrame()) != null) {
                if (frame.samples != null) {
                    recorder.record(frame);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            success = false;
        } finally {
            try {
                if (recorder != null) {
                    recorder.stop();
                    recorder.release();
                }
                grabber.stop();
                grabber.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return success;
    }

    /**
     * 将 MP3 文件转换为 WAV 文件
     */
    public boolean convertMp3ToWav(String inputMp3FilePath, String outputWavFilePath) {

        try {
            // 加载 MP3 文件
            File inputFile = new File(inputMp3FilePath);
            AudioInputStream mp3InputStream = AudioSystem.getAudioInputStream(inputFile);

            // 获取音频格式
            AudioFormat sourceFormat = mp3InputStream.getFormat();
            System.out.println("源音频格式: " + sourceFormat);

            // 定义目标音频格式（PCM 编码的 WAV）
            AudioFormat targetFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, // 编码格式
                    sourceFormat.getSampleRate(),    // 采样率
                    16,                              // 采样大小（16 位）
                    sourceFormat.getChannels(),      // 通道数
                    sourceFormat.getChannels() * 2,  // 帧大小
                    sourceFormat.getSampleRate(),    // 帧速率
                    false                           // 是否大端字节序
            );

            // 将 MP3 音频流转换为目标格式
            AudioInputStream pcmInputStream = AudioSystem.getAudioInputStream(targetFormat, mp3InputStream);

            // 写入 WAV 文件
            File outputFile = new File(outputWavFilePath);
            AudioSystem.write(pcmInputStream, AudioFileFormat.Type.WAVE, outputFile);

            // 关闭流
            pcmInputStream.close();
            mp3InputStream.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public boolean separateAudio(File inputFile, File outputVocalsFile, File outputAccompanimentFile) {
        try {
            FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
            grabber.start();

            // 获取音频参数
            int audioChannels = grabber.getAudioChannels();
            int sampleRate = grabber.getSampleRate();

            // 检查是否为立体声
            if (audioChannels != 2) {
                System.err.println("输入音频不是立体声，无法分离左右声道！");
                return false;
            }

            // 初始化录音器
            FFmpegFrameRecorder vocalsRecorder = new FFmpegFrameRecorder(outputVocalsFile, 1); // 单声道
            vocalsRecorder.setSampleRate(sampleRate);
            vocalsRecorder.setAudioChannels(1);
            vocalsRecorder.start();

            FFmpegFrameRecorder accompanimentRecorder = new FFmpegFrameRecorder(outputAccompanimentFile, 1); // 单声道
            accompanimentRecorder.setSampleRate(sampleRate);
            accompanimentRecorder.setAudioChannels(1);
            accompanimentRecorder.start();

            Frame frame;
            while ((frame = grabber.grabFrame()) != null) {
                if (frame.samples != null) {
                    // 将 Buffer 转换为 ShortBuffer
                    ShortBuffer shortBuffer = (ShortBuffer) frame.samples[0];
                    short[] samples = new short[shortBuffer.remaining()];
                    shortBuffer.get(samples);

                    // 分离左右声道
                    short[] vocals = new short[samples.length / 2];
                    short[] accompaniment = new short[samples.length / 2];

                    for (int i = 0; i < samples.length; i += 2) {
                        vocals[i / 2] = samples[i];          // 左声道
                        accompaniment[i / 2] = samples[i + 1]; // 右声道
                    }

                    // 创建新的 Frame 并录制
                    Frame vocalsFrame = new Frame();
                    vocalsFrame.samples = new ShortBuffer[]{ShortBuffer.wrap(vocals)};
                    vocalsFrame.sampleRate = sampleRate;
                    vocalsFrame.audioChannels = 1;
                    vocalsRecorder.record(vocalsFrame);

                    Frame accompanimentFrame = new Frame();
                    accompanimentFrame.samples = new ShortBuffer[]{ShortBuffer.wrap(accompaniment)};
                    accompanimentFrame.sampleRate = sampleRate;
                    accompanimentFrame.audioChannels = 1;
                    accompanimentRecorder.record(accompanimentFrame);
                }
            }

            grabber.stop();
            vocalsRecorder.stop();
            accompanimentRecorder.stop();
            return true;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public void recognize(String audioFilePath, String outputTextFilePath) {
        try {
            // 创建Recognition实例
            Recognition recognizer = new Recognition();
            // 创建RecognitionParam
            RecognitionParam param =
                    RecognitionParam.builder()
                            // 若没有将API Key配置到环境变量中，需将下面这行代码注释放开，并将apiKey替换为自己的API Key
                            .apiKey(UrlConstant.DASH_SCOPE_API_KEY)
                            .model("paraformer-realtime-v2")
                            .format("wav")
                            .sampleRate(16000)
                            // “language_hints”只支持paraformer-v2和paraformer-realtime-v2模型
                            .parameter("language_hints", new String[]{"zh", "en"})
                            .build();
            try {
                System.out.println("识别结果：" + recognizer.call(param, new File(audioFilePath)));
            } catch (Exception e) {
                System.out.println("error: " + e);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
